Welcome to the scripting installment of this manual. Linden Scripting Language (LSL) allows residents of Second Life and OpenSim to program the three dimensional objects around them. Without this programming, objects built in Second Life and OpenSim are motionless and non-interactive. To make an object interactive, simply add a script. Using LSL, you can create cars, planes, amusement park rides, weapons, and other entertainment devices. You can also use it to make PowerPoint (and other) presentations available in a virtual environment.

Here are some good resources for beginners:

LSL wiki - http://wiki.secondlife.com/wiki/LSL_Tutorial

Video Tutorials - http://wiki.secondlife.com/wiki/Video_Tutorials

Important Concepts


Before you start scripting, you need to understand a few important concepts and terminologies. (Click the links for full details.)

Inventory and Scripts


Each prim can store other things inside itself. You can think of the prim's inventory as its pocket or closet. In its inventory, a prim can store other prims, objects, notecards, and scripts. In Second Life, a script inside a prim can control the prim's position and orientation, color, shape, and size, and other physical properties. It can enable the prim's response to commands, reaction to the environment, or any other interactivity provided by the scripting language.

Physics and Vehicles


An object has a number of properties, including material. Material is especially important when you are scripting an object that behaves like a physical object, for example, a car. Any moving object that has physical properties is called a vehicle. See physics. Also, please note that the physics engine used by Second Life is Havok (software).




The above information can get you started in LSL scripting, but is not all there is to know! Learning LSL scripting requires experience. As you script, you will pick up many more details of the context and environment you can use LSL to control. LSL scripting is very much a trial and error, learn as you go, process.

States and Events


In LSL, most scripts sit idle until they receive some input, or detect changes in their environments. At any moment, the script is in some state, and will react to events or inputs according to some scheme defined by the programmer. However, a script can also contain two or more different states, and react differently to events or inputs depending on its particular state. One common abstract model that is used in such cases is called a Finite State Machine.

For example, a door might be in a waiting state, and ignore all inputs except being touched. Once touched, it goes to the open state, in which it ignores being touched, but monitors which avatars pass through it. After a while, it changes to the closing state during which it closes, and then returns to the waiting state. States are not the only way to represent this kind of behavior, but in some cases they are a very good way.

In LSL, a state is a specified section of code within which all events are specified. The main state that is required by all LSL scripts is called default. All scripts must have a default state, and every state must have at least one event.

Here is a link to more detailed information on the "State Machine" that is LSL:

http://lslwiki.net/lslwiki/wakka.php?wakka=state

Running LSL Scripts


Second Life includes a facility for defining scripts within existing objects. To create an object, start Second Life and log in. Right-click on virtual ground or water and select Build from the menu that appears. An object manipulation menu will open on your screen and your cursor will change to a magic wand when you hover it over the ground again.

Left-click again on the ground (or water). You will hear a rumble and an object will appear. When you have produced your cube, cone, sphere, or other three-dimensional geometric figure, return to the object manipulation menu.

Left-click on the Content tab. This directory is where scripts, if any are associated with an object, will appear.

Left-click on the New Script button, and a Script editing window will open. The editing window has a script editing area, where you can type or paste in a new script, and buttons for saving the script, undoing changes, etc.

The script editing area should contain the following script:

default
{
    state_entry()
    {
        llSay( 0, "Hello, Avatar!");
    }
 
    touch_start(integer total_number)
    {
        llSay( 0, "Touched.");
    }
}
 

Left-Click on the Save button. The message "Compile successful, saving..." should appear in the box below the script editing area. After a short pause you should see "Save complete" appear in the box.

Once the script is saved, you will see the message "Hello, Avatar!" appear in the lower-left-hand corner of your screen. This message indicates that the script has started and is waiting for touch events.

To test the object's responsiveness to touch, close both the script editing and object manipulation windows, and right-click on the object. Select Touch from the menu. You should see "Object: Touched" appear in the lower-left-hand corner.

Entering and Running a Simple Script


Here is a very simple program that changes the color and size of the object every time the object is touched.

integer counter;
 
default
{
    state_entry()
    {
        llSay( 0, "Hello, Avatar! Touch to change color and size.");
        counter = 0;
    }
 
    touch_start(integer total_number)
    {   // do these instructions when the object is touched.
        counter = counter + 1;
 
        // choose three random RGB color components between 0. and 1.0.
        float redness = llFrand( 1.0 );
        float greenness = llFrand( 1.0 );
        float blueness = llFrand( 1.0 );
 
        // combine color components into a vector and use that vector
        // to set object color.
        vector prim_color = < redness, greenness, blueness >;
        llSetColor( prim_color, ALL_SIDES );   // set object color to new color.
 
        // choose a random number between 0. and 10. for use as a scale factor.
        float new_scale = llFrand(10.0) + 1.0;
        llSetScale(< new_scale, new_scale, new_scale > ); // set object scale.
        llSay( 0, "Touched by angel number " + (string)counter);
    }
}

Your boxes will have different colors and sizes and this program will count the number of times the object is touched, and write the number in the lower-left-hand corner of the screen. To insert this script into the object you just created, right-click on the object, reopen the Script editing window, paste this script into the Script editing area, and click Save. When the script has been saved, test it by right-clicking on the object and choosing Touch, as before.

You may have to do some debugging to correct errors, and when you finally get things running correctly, you may want to right-click on the object and choose Take to move the object into your Inventory. Objects in your inventory will remain there even after you log off, and will be available when you log back in. Later, you may move copies of these objects back into Second Life, and reuse them.

Changing an Object's Appearance Over Time


Here is a script that changes the color and size of an object, every two seconds for about 40 seconds, beginning when the object is touched.

integer counter;
integer second;
 
default
{
    state_entry()
    {
        llSay( 0, "Hello, Avatar! Touch to change color and size.");
        counter = 0;
    }
 
    touch_start(integer total_number)
    {
        counter = counter + 1;
 
        llSay( 0, "Touched by angel number " + (string)counter);
 
        llSetTimerEvent( 2 );  // create a "timer event" every 2 seconds.
    }
 
    timer()  // do these instructions every time the timer event occurs.
    {
        second++;
 
        // choose three random RGB color components between 0. and 1.0.
        float red = llFrand( 1.0 );
        float green = llFrand( 1.0 );
        float blue = llFrand( 1.0 );
 
        // combine color components into a vector and use that vector
        // to set object color.
        vector prim_color = < red, green, blue >;
        llSetColor( prim_color, ALL_SIDES );   // set object color to new color.
 
        // a choose random number between 0. and 10 for use as a scale factor.
        float new_scale = llFrand( 10.0 );
        llSetScale(< new_scale, new_scale, new_scale > ); // set object scale.
 
        if ( second > 19 )  // then time to wrap this up.
        {
            // turn object black, print "resting" message, and reset object....
            llSetColor( < 0, 0, 0 >, ALL_SIDES );
 
            llSay( 0, "Object now resting and resetting script." );
            llResetScript();  // return object to ready state.
        }
    }
}
 

When a touch_start event occurs, the program starts a timer that runs out every two seconds, causing a timer event. Whenever a timer event occurs, the script segment within the brackets below the string "timer()" is executed. The timer() section counts the number of times it is activated, and resets the script after twenty activations.

If multiple avatars touch the object at the same time, strange behavior may occur. Such an event may be monitored and controlled by using the total_number variable passed to touch_start.


Changing an Object's Position Over Time



A script may change the position of its object by using the llSetPos() function. Here is a script that repositions an object using llSetPos() once a second for twenty seconds. The new positions are chosen by incrementing the starting position using a vector constructed during each iteration from three random values between 0.0 and 10.0 meters.

integer counter;
integer second;
vector startPosition;
 
default
{
    state_entry()
    {
        llSay( 0, "Hello, Avatar! Touch to change position.");
        counter = 0;
        startPosition = llGetPos();
    }
 
    touch_start(integer total_number)
    {
        counter = counter + 1;
 
        llSay( 0, "Touched by angel number " + (string)counter);
 
        llSetTimerEvent( 1 );  // arrange for a "timer event" every second.
    }
 
    timer()  // do these instructions every time the timer event occurs.
    {
        second++;
 
        // choose three random distances between 0. and 10.0.
        float X_distance = llFrand( 10.0 );
        float Y_distance = llFrand( 10.0 );
        float Z_distance = llFrand( 10.0 );
 
        // combine these distance components into a vector and use it
        // to increment the starting position and reposition the object.
        vector increment = < X_distance, Y_distance, Z_distance >;
        vector newPosition = startPosition + increment;
        llSetPos( newPosition );   // reposition object.
 
        if ( second > 19 )  // then time to wrap this up.
        {
            // move object back to starting position...
            while ( llVecDist( llGetPos(), startPosition ) > 0.001)
            {
                llSetPos( startPosition );
            }
 
            llSay( 0, "Object now resting and resetting script." );
            llResetScript();  // return object to ready state.
        }
    }
}
 

To help you keep track of the object, it is repositioned to the starting position before the script re-initializes.

The motion generated by random repositioning is, of course, quite erratic. To cause an object to move more "naturally" one must choose subsequent positions more carefully. New positions must lie along a movement track, and be sufficiently close to one another that jerkiness is either not apparent or minimized.

Summary


These are some basic examples of what can be accomplished in Scripting. Here is a link to the script archives. There are many varieties of scripts there that can be reverse engineered to fit your specific needs.

http://ucslteam.wikispaces.com/Scripts+Archive


Note that some functions that work in Second Life will not work in OpenSim. Here is a link that explain which functions do not work in OpenSim (or have yet to be implemented on that platform).

http://opensimulator.org/wiki/LSL_Status/Functions

Please note that C/C++ will compile and work in OpenSim (though not in Second Life).

Continue to Chapter 6 - Managing Land